package ua.org.nuos.sdms.middle.entity;

import ua.org.nuos.sdms.middle.entity.enums.EmailStatus;
import ua.org.nuos.sdms.middle.entity.enums.Role;

import javax.persistence.*;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Size;
import java.io.Serializable;
import java.util.LinkedList;
import java.util.List;

/**
 * Created by IntelliJ IDEA.
 * User: dio
 * Date: 09.10.11
 * Time: 20:26
 * User of the system
 */
@Entity
@Table(name = "user_")
@NamedQueries(value = {
        @NamedQuery(name = User.QUERY_FIND_BY_EMAIL, query = "SELECT DISTINCT u FROM User u WHERE u.email = :email ORDER BY u.lastName"),
        @NamedQuery(name = User.QUERY_FIND_BY_NAME, query = "SELECT DISTINCT u FROM User u WHERE LOWER(u.firstName) = :name OR LOWER(u.lastName) = :name ORDER BY u.lastName")
})
public class User implements Serializable {

    private static final String CUSTOM_SEQUENCE = "custom_sequence";

    public static final String QUERY_FIND_BY_EMAIL = "findUserByEmail";
    public static final String QUERY_FIND_BY_NAME = "findUsersByName";

    @Id
    @Column(name = "id")
    @SequenceGenerator(name = CUSTOM_SEQUENCE, initialValue = 20)
    @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = CUSTOM_SEQUENCE)
    private long id;

    @NotNull
    @Size(max = 255)
    @Column(name = "email", nullable = false, unique = true, length = 255)
    private String email;

    @NotNull
    @Column(name = "email_status", nullable = false)
    @Enumerated(value = EnumType.STRING)
    private EmailStatus emailStatus;

    @Size(max = 255)
    @Column(name = "first_name", length = 255)
    private String firstName;

    @Size(max = 255)
    @Column(name = "last_name", length = 255)
    private String lastName;

    @NotNull
    @Size(max = 255)
    @Column(name = "password", nullable = false, length = 255)
    private String password;

    @OneToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "last_group_id")
    private Group lastGroup;

    @ElementCollection
    @CollectionTable(name = "user_role", joinColumns = @JoinColumn(name = "user_id"))
    @Column(name = "role")
    @Enumerated(value = EnumType.STRING)
    @Size(min = 1)
    private List<Role> roles;

    public User() {
        this.roles = new LinkedList<Role>();
    }

    public String getEmail() {
        return email;
    }

    public void setEmail(String email) {
        this.email = email;
    }

    public EmailStatus getEmailStatus() {
        return emailStatus;
    }

    public void setEmailStatus(EmailStatus emailStatus) {
        this.emailStatus = emailStatus;
    }

    public String getFirstName() {
        return firstName;
    }

    public void setFirstName(String firstName) {
        this.firstName = firstName;
    }

    public String getLastName() {
        return lastName;
    }

    public void setLastName(String lastName) {
        this.lastName = lastName;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    public Group getLastGroup() {
        return lastGroup;
    }

    public void setLastGroup(Group lastGroup) {
        this.lastGroup = lastGroup;
    }

    public String getFullName() {
        String name = "";
        if (firstName != null && !firstName.isEmpty()) {
            name += firstName;
        }
        if (lastName != null && !lastName.isEmpty()) {
            name += name.isEmpty() ? "" : " ";
            name += lastName;
        }
        if (name.isEmpty()) {
            return email;
        } else {
            return name;
        }
    }

    public long getId() {
        return id;
    }

    public void setId(long id) {
        this.id = id;
    }

    public List<Role> getRoles() {
        return roles;
    }

    public void setRoles(List<Role> roles) {
        this.roles = roles;
    }

    public void addRole(Role role) {
        if (!roles.contains(role)) {
            roles.add(role);
        }
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;

        User user = (User) o;

        if (id != user.id) return false;
        if (email != null ? !email.equals(user.email) : user.email != null) return false;
        if (firstName != null ? !firstName.equals(user.firstName) : user.firstName != null) return false;
        if (lastGroup != null ? !lastGroup.equals(user.lastGroup) : user.lastGroup != null) return false;
        if (lastName != null ? !lastName.equals(user.lastName) : user.lastName != null) return false;
        if (password != null ? !password.equals(user.password) : user.password != null) return false;
        if (emailStatus != null ? !emailStatus.equals(user.emailStatus) : user.emailStatus != null) return false;
        if ((roles != null && !roles.isEmpty()) ? !roles.equals(user.roles) : (user.roles != null && !user.roles.isEmpty()))
            return false;

        return true;
    }

    @Override
    public int hashCode() {
        int result = (int) (id ^ (id >>> 32));
        result = 31 * result + (email != null ? email.hashCode() : 0);
        result = 31 * result + (emailStatus != null ? emailStatus.hashCode() : 0);
        result = 31 * result + (firstName != null ? firstName.hashCode() : 0);
        result = 31 * result + (lastName != null ? lastName.hashCode() : 0);
        result = 31 * result + (password != null ? password.hashCode() : 0);
        result = 31 * result + (lastGroup != null ? lastGroup.hashCode() : 0);
        result = 31 * result + (roles != null ? roles.hashCode() : 0);
        return result;
    }

    @Override
    public String toString() {
        return "User{" +
                "id=" + id +
                ", email='" + email + '\'' +
                ", emailStatus='" + emailStatus + '\'' +
                ", firstName='" + firstName + '\'' +
                ", lastName='" + lastName + '\'' +
                ", password='" + password + '\'' +
                ", lastGroup=" + lastGroup +
                ", roles=" + roles.toString() +
                '}';
    }
}
